#include "can_init.h"
#include"ringbuffer.h"
#include"ip_can_fifo.h"
#include"can_sys_t.h"

flag_conuter_inter=0;
static void send_handler(void *CallBackRef)
{

}

static void recv_handler(void *CallBackRef)
{
	int status;
    u32 rxFrame[4];
   // xil_printf("CAN recv_handler start\r\n");
    drv_can_t *CanPtr = (drv_can_t *)CallBackRef;
    XCan *can = &CanPtr->can;
    flag_conuter_inter ++ ;
    int channel_id = -1;
    for (int i = 0; i < MAX_CAN_DEVICES; i++)
    {
        if (&can_system.drv_can[i] == CanPtr)
        {
            channel_id = i;
            break;
        }
    }

    if (channel_id == -1)
    {
        xil_printf("Error: Cannot determine CAN channel ID\r\n");
        return;
    }
    int packet_count = 0;

    while (XCan_IsRxEmpty(can) != 1 && packet_count < MAX_PACKETS_PER_INTERRUPT)
    {

        status = XCan_Recv(can, rxFrame);
        packet_count++;
        if (status == XST_SUCCESS)
        {
            can_rx_data_t rx_data;
            rx_data.channel_id = channel_id;
            rx_data.id = rxFrame[0];
            rx_data.dlen = rxFrame[1] >> 28;
            rx_data.dw1 = rxFrame[2];
            rx_data.dw2 = rxFrame[3];
            rx_data.channel_id = channel_id;
            if (CanPtr->rx_buffer != NULL)
            {
            	uint32_t bytes_written = ringbuffer_put(CanPtr->rx_buffer, &rx_data, 1);

            	if (bytes_written != 1)
            	{
            	    xil_printf("Data stored in ring buffer, channel %d\r\n", channel_id);
            	}
             }
            else
            {
            	 xil_printf("Error: No ring buffer assigned for channel %d\r\n", channel_id);
            }


        } else {
            xil_printf("Error receiving CAN frame: status = %d\r\n", status);
            break;
        }
    }
}
 static void event_handler(void *CallBackRef, u32 IntrMask)
 {
 	int status;
 	drv_can_t *CanPtr = (drv_can_t *)CallBackRef;

 	if (IntrMask & XCAN_IXR_BSOFF_MASK) { /* Enter Bus off status */
 		/*
 		 * Entering Bus off status interrupt requires
 		 * the CAN device be reset and re-configurated.
 		 */
 		XCan_Reset(&CanPtr->can);


// 		while(1){
// 			status = CAN_Init(CanPtr);
// 			if(!status){
// 				break;
// 			} else {
// 				CanPtr->can_event.ixr_bsoff_count += 1;
// 			}
// 		}

 		return;
 	}

 	if(IntrMask & XCAN_IXR_RXOFLW_MASK) { /* RX FIFO Overflow Interrupt */
 		/*
 		 * Code to handle RX FIFO Overflow
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_rxoflw_count += 1;
 	}

 	if(IntrMask & XCAN_IXR_RXUFLW_MASK) { /* RX FIFO Underflow Interrupt */
 		/*
 		 * Code to handle RX FIFO Underflow
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_rxuflw_count += 1;
 	}

 	if(IntrMask & XCAN_IXR_TXBFLL_MASK) { /* TX High Priority Full Intr */
 		/*
 		 * Code to handle TX High Priority Buffer Full
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_txbfll_count += 1;
 	}

 	if(IntrMask & XCAN_IXR_TXFLL_MASK) { /* TX FIFO Full Interrupt */
 		/*
 		 * Code to handle TX FIFO Full
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_txfll_count += 1;
 	}

 	if (IntrMask & XCAN_IXR_WKUP_MASK) { /* Wake up from sleep mode */
 		/*
 		 * Code to handle Wake up from sleep mode
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_wkup_count += 1;
 	}

 	if (IntrMask & XCAN_IXR_SLP_MASK) { /* Enter sleep mode */
 		/*
 		 * Code to handle Enter sleep mode
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_slp_count += 1;
 	}

 	if (IntrMask & XCAN_IXR_ARBLST_MASK) { /* Lost bus arbitration */

 		/*
 		 * Code to handle Lost bus arbitration
 		 * Interrupt should be put here.
 		 */
 		CanPtr->can_event.ixr_arblst_count += 1;
 	}

 	return ;
 }
 static void error_handler(void *CallBackRef, u32 ErrorMask)
 {
 	drv_can_t *CanPtr = (drv_can_t *)CallBackRef;

 	if(ErrorMask & XCAN_ESR_ACKER_MASK) {
 		/*
 		 * ACK Error handling code should be put here.
 		 */
 		CanPtr->can_error.esr_acker_count += 1;
 	}

 	if(ErrorMask & XCAN_ESR_BERR_MASK) {
 		/*
 		 * Bit Error handling code should be put here.
 		 */
 		CanPtr->can_error.esr_berr_count += 1;
 	}

 	if(ErrorMask & XCAN_ESR_STER_MASK) {
 		/*
 		 * Stuff Error handling code should be put here.
 		 */
 		CanPtr->can_error.esr_ster_count += 1;
 	}

 	if(ErrorMask & XCAN_ESR_FMER_MASK) {
 		/*
 		 * Form Error handling code should be put here.
 		 */
 		CanPtr->can_error.esr_fmer_count += 1;
 	}

 	if(ErrorMask & XCAN_ESR_CRCER_MASK) {
 		/*
 		 * CRC Error handling code should be put here.
 		 */
 		CanPtr->can_error.esr_crcer_count += 1;
 	}
 	return ;
 }

int CAN_Init(drv_can_t *pdrv_can) {
    int Status;
    XCan *can = &pdrv_can->can;
    memset(pdrv_can, 0x0, sizeof(drv_can_t));

    Status = XCan_Initialize(can, pdrv_can->id);
    if (Status != XST_SUCCESS) {
        xil_printf("CAN  0 Initialization Failed\r\n");
        return Status;
    }

    Status = XCan_SelfTest(can);
    if (Status != XST_SUCCESS) {
        xil_printf("CAN Self-Test Failed\r\n");
        return Status;
    }

    CAN_SetBaudRate(pdrv_can, 500000);

	XCan_SetHandler(can, XCAN_HANDLER_SEND,
			(void *)send_handler, (void *)pdrv_can);
	XCan_SetHandler(can, XCAN_HANDLER_RECV,
			(void *)recv_handler, (void *)pdrv_can);
	XCan_SetHandler(can, XCAN_HANDLER_ERROR,
			(void *)error_handler, (void *)pdrv_can);
	XCan_SetHandler(can, XCAN_HANDLER_EVENT,
			(void *)event_handler, (void *)pdrv_can);

    /****************************************/
	SendDone = FALSE;
	RecvDone = FALSE;
	LoopbackError = FALSE;

	if (CAN_SetMode(pdrv_can, XCAN_MODE_NORMAL) != XST_SUCCESS) {

	    xil_printf("Failed to set CAN mode\r\n");
	}

    XCan_InterruptEnable(can, XCAN_IXR_ALL);

    return XST_SUCCESS;
}


void CAN_SetBaudRate(drv_can_t *drv_can, u32 BaudRate) {
	XCan_Config *config;
	config = XCan_LookupConfig(drv_can->id);
	    if (config == NULL) {
	        xil_printf("deault: no find CAN %d config messages\r\n", drv_can->id);
	        return ;
	    }

    XCan_EnterMode(&drv_can->can, XCAN_MODE_CONFIG);
    while (XCan_GetMode(&drv_can->can) != XCAN_MODE_CONFIG);
    xil_printf("BaudRate CAN %d \r\n", BaudRate);

    switch(BaudRate)
    {
    		case 1000000:  // 1Mbps
    			xil_printf(" CAN_SetBaudRate set 1M sucessfull \r\n");// 1M
                XCan_SetBaudRatePrescaler(&drv_can->can, 2);
                XCan_SetBitTiming(&drv_can->can, 0, 2, 3 );
                break;
    		case 800000:    //800k
    			xil_printf(" CAN_SetBaudRate set 800K sucessfull \r\n");// 800k
    			XCan_SetBaudRatePrescaler(&drv_can->can, 2);
    			XCan_SetBitTiming(&drv_can->can, 0, 4, 3);
    			break;
            case 500000:
            	xil_printf(" CAN_SetBaudRate set 500k sucessfull \r\n");// 500k
                XCan_SetBaudRatePrescaler(&drv_can->can, 2);
                XCan_SetBitTiming(&drv_can->can, 0, 4, 9);
                break;
            case 250000:   // 250k
            	xil_printf(" CAN_SetBaudRate set 250k sucessfull \r\n");// 250k
                XCan_SetBaudRatePrescaler(&drv_can->can, 11);
                XCan_SetBitTiming(&drv_can->can, 0, 3, 2);
                break;
            case 125000:   // 125k
            	xil_printf(" CAN_SetBaudRate set 125k sucessfull \r\n");// 125k
                XCan_SetBaudRatePrescaler(&drv_can->can, 11);
                XCan_SetBitTiming(&drv_can->can, 0, 5, 8);
                break;
            case 100000:   // 100k
            	xil_printf(" CAN_SetBaudRate set 100k sucessfull \r\n");// 100k
                XCan_SetBaudRatePrescaler(&drv_can->can, 23);
                XCan_SetBitTiming(&drv_can->can, 0, 3, 4);
                break;
            case 50000:    // 50k
            	xil_printf(" CAN_SetBaudRate set 50k sucessfull \r\n");// 50k
                XCan_SetBaudRatePrescaler(&drv_can->can, 47);
                XCan_SetBitTiming(&drv_can->can, 0, 3, 4);
                break;
            case 20000:    //20k
            	xil_printf(" CAN_SetBaudRate set 20k sucessfull \r\n");// 20k
            	XCan_SetBaudRatePrescaler(&drv_can->can, 119);
            	XCan_SetBitTiming(&drv_can->can, 0, 3, 4);
            	break;
            case 10000:    // 10k
            	xil_printf(" CAN_SetBaudRate set 10k sucessfull \r\n");// 10k
                XCan_SetBaudRatePrescaler(&drv_can->can, 239);
                XCan_SetBitTiming(&drv_can->can, 0, 3, 4);
                break;
            case 5000:     // 5k
            	xil_printf(" CAN_SetBaudRate set 5k sucessfull \r\n");// 5k
                XCan_SetBaudRatePrescaler(&drv_can->can, 239);
                XCan_SetBitTiming(&drv_can->can, 0, 3, 14);
                break;
            default:
            	XCan_SetBaudRatePrescaler(&drv_can->can, 2);
            	XCan_SetBitTiming(&drv_can->can, 0, 4, 9);
            	break ;
    }
}
int CAN_SetMode(drv_can_t *drv_can, u8 Mode) {
    int timeout = 100000;

    if (drv_can == NULL) {
        xil_printf("Error: CAN_SetMode received NULL pointer\r\n");
        return XST_FAILURE;
    }

    XCan_EnterMode(&drv_can->can, Mode);

    while (XCan_GetMode(&drv_can->can) != Mode) {
        if (--timeout == 0) {
            xil_printf("Error: CAN mode change timed out\r\n");
            return XST_FAILURE;
        }
    }

    xil_printf("CAN_SetMode successful (Mode: %d)\r\n", Mode);
    return XST_SUCCESS;
}



